    /****************************************************************** 
* Created by: GOH CHEE HONG                                      
                                          
 * Date of last modification: 06/SEP/2008
 * Description: Event argument to notify that the program has receive
 * search result from the network.
 * 
 ******************************************************************/
/******************************************************************
 * Created by: DO HOANG HAI                                       
 * Date of Creation: 14/Jan/2008                                              
 * Date of last modification: 29/Dec/2007
 *                                                                
 * Description: Event argument to notify that the program has receive
 * search result from the network.
 * 
 ******************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Xml;
using System.Xml.Serialization;
using Pbdms.NetworkDealer.EventArgs;
using Pbdms.NetworkDealer.Requests;


using System.Windows.Forms;
using System.Security.Cryptography;
using Org.BouncyCastle.Bcpg.OpenPgp;
using System.Threading;
using System.ComponentModel;
using Pbdms.Common.SharedVariables;
using Pbdms.Common.DataObject;
namespace Pbdms.NetworkDealer
{
    /// <summary>
    /// this class's responsibility is to deal with any incomming messages from the network
    /// as well as sending out messages, cooperate with Network Controller to perform 
    /// other realted functions
    /// </summary>
    public class NetworkDealer
    {
        System.Collections.ArrayList arlOfReceivedRequest;
     
        public const int SEARCH_REQUEST = 1;
        public const int DOWNLOAD_REQUEST = 2;
        public const int SEARCH_RESULT = 3;
        public const int DOWNLOAD_REQUEST_GRANTED = 4;
        public const int DOWNLOAD_REQUEST_REJECTED =5;
        public const int DOWNLOAD_CLIENT_READY = 6;
        public const int BROWSE_REQUEST = 7;
        public const int BROWSE_RESULT_BUDDY = 8;
        public const int BROWSE_RESULT_ITEMS = 9;

        #region chee hong new int


        public const int FEED_REQUEST = 10;
        public const int FEED_RESPONSE = 11;
        public const int VIEWITEM_REQUEST = 12;
        public const int VIEWITEM_RESPONSE = 13;
        public const int VERIFYKEY_REQUEST = 14;
        public const int VERIFYKEY_RESPONSE = 15;
        public const int SEND_A_MESSAGE = 16;
        public const int SEND_A_MESSAGE_REPLY = 17;
        public const int TRANSFER_FILE_REQUEST = 18;
        public const int TRANSFER_FILE_REQUEST_GRANTED = 19;
        public const int TRANSFER_FILE_REQUEST_REJECTED = 20;
    


         #endregion 
        AuthTcpServer authServer;
        //listen port
        public const int LISTEN_PORT = 5150;
     

        //two files to be downloaded when a download request is sent to server.
        public String currentFileToDownload1;
        public String currentFileToDownload2;
        
   
        public static IPAddress ipAddMyComputer = Common.Global.getIP();//System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName())[0];

        
        /// <summary>
        /// define a handle for search request
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void SearchRequestReceivedEventHandler(object sender, SearchRequestReceivedEventArgs e);
        /// <summary>
        /// define a handler for SearchResultReceived event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void SearchResultReceivedEventHandler(object sender, SearchResultReceivedEventArgs e);
        /// <summary>
        /// define a handler for DownloadClientReady event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        
   

        public event SearchRequestReceivedEventHandler SearchRequestReceived;
        /// <summary>
        /// deifnes SearchResultlReceived event
        /// </summary>
        public event SearchResultReceivedEventHandler searchResultReceived;


       

        
        private SecretKeyControl secretKeyControl;
        private PublicKeysControl publicKeyControl;
        private FriendsControl friendsControl;




        #region new events
        public delegate void DownloadRequestHandler(object sender, NetworkMessage message);
        public event DownloadRequestHandler DownloadRequest;
        public delegate void VerifyKeyRequestHandler(object sender, NetworkMessage message);
        public event VerifyKeyRequestHandler VerifyKeyRequest;
        public delegate void VerifyKeyResponseHandler(object sender, NetworkMessage message);
        public event VerifyKeyResponseHandler VerifyKeyResponse;
        public delegate void FeedRequestReceivedHandler(object sender, NetworkMessage message);
        public event FeedRequestReceivedHandler FeedRequestReceived;
        public delegate void ViewAnItemRequestHandler(object sender, NetworkMessage message);
        public event ViewAnItemRequestHandler ViewAnItemRequest;
        public delegate void InstantMessageReceivedHandler(object sender, NetworkMessage message);
        public event InstantMessageReceivedHandler InstantMessageReceived;
        public delegate void FileTransferRequestReceivedHandler(object sender, NetworkMessage message);
        public event FileTransferRequestReceivedHandler FileTransferRequestReceived;
        public delegate void BrowseRequestReceivedHandler(object sender, NetworkMessage message);
        public event BrowseRequestReceivedHandler browseRequestReceived;
        public delegate void BrowseResultBuddyReceivedEventHandler(object sender, SearchResult searchObj);
        public event BrowseResultBuddyReceivedEventHandler browseResultBuddyReceived;
        
        #endregion


        #region

        #endregion
        public NetworkDealer(SecretKeyControl secretKeyControl, PublicKeysControl publicKeyControl, FriendsControl friendsControl)
        {
            this.secretKeyControl = secretKeyControl;
            this.publicKeyControl = publicKeyControl;
            this.friendsControl = friendsControl;
            arlOfReceivedRequest = new System.Collections.ArrayList();
            System.Threading.ThreadStart thsOldRequestRemover = new System.Threading.ThreadStart(removeOldRequest);
            System.Threading.Thread thOldRequestRemover = new System.Threading.Thread(thsOldRequestRemover);
            thOldRequestRemover.Start();
        }
        /// <summary>
        /// remove old request upon timeout
        /// </summary>
        public void removeOldRequest()
        {
            System.Timers.Timer tmer = new System.Timers.Timer(5000);
            tmer.Elapsed += new System.Timers.ElapsedEventHandler(tmer_Elapsed);
            tmer.Start();
        }
        /// <summary>
        /// handles Elapsed event triggered by the timer
        /// Tasks: check old requests and remove them from the list of requests
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void tmer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (arlOfReceivedRequest.Count > 0)
            {
                ReceivedRequest[] arrTemp = new ReceivedRequest[arlOfReceivedRequest.Count];
                arlOfReceivedRequest.CopyTo(arrTemp);
                for (int i = 0; i < arrTemp.Length; i++)
                {
                    ReceivedRequest rRequest = (ReceivedRequest)(arrTemp[i]);
                    if (DateTime.Now.Ticks - rRequest.ReceivedTime.Ticks > 30)
                    {
                        rRequest = null;
                    }
                }
                arlOfReceivedRequest = new System.Collections.ArrayList();
                for (int i = 0; i < arrTemp.Length; i++)
                {
                    if (arrTemp[i] != null)
                    {
                        arlOfReceivedRequest.Add(arrTemp[i]);
                    }
                }
            }
                        
        }

        /// <summary>
        /// force the program to stop listening on the port
        /// </summary>
        public void stopListening()
        {
            if ( authServer != null)
            {
                 authServer.Close();
                
            }
        }




        protected void onBrowseResultBuddyReceived(object networkDealer, Pbdms.NetworkDealer.EventArgs.BrowseResultBuddyReceivedEventArgs e)
        {
            //if (e != null)
                //browseResultBuddyReceived(networkDealer, e);
        }


        /// <summary>
        /// trigger the SearchResultReceived event
        /// </summary>
        /// <param name="networkDealer"></param>
        /// <param name="searchResultReceivedEventArgs"></param>
        protected void onSearchResultReceived(object networkDealer, SearchResultReceivedEventArgs searchResultReceivedEventArgs)
        {
            if (searchResultReceivedEventArgs != null)
            {
                //trigger the event
                searchResultReceived(networkDealer, searchResultReceivedEventArgs);
            }
        }





       
        /// <summary>
        /// check a request to see whether it is a duplicated request
        /// </summary>
        /// <param name="rRequest"></param>
        /// <returns></returns>
        private bool isDuplicatedRequest(ReceivedRequest rRequest)
        {
            if (arlOfReceivedRequest.Count > 0)
            {
                for (int i = 0; i < arlOfReceivedRequest.Count; i++)
                {
                    ReceivedRequest oldRequest = (ReceivedRequest)(arlOfReceivedRequest[i]);
                    if (rRequest.IpFrom.Equals(oldRequest.IpFrom) && rRequest.RequestId == oldRequest.RequestId)
                        return true;
                }
            }
            return false;
        }


        private void handleBrowseResultBuddyReceived(IPAddress ipAdd, string msg)
        {
            BrowseResultBuddyReceivedEventArgs e = new BrowseResultBuddyReceivedEventArgs(msg);
            onBrowseResultBuddyReceived(this, e);
        }

        private void handleBrowseResultItemReceived(IPAddress ipAdd, string msg)
        {
            try
            {
                //deserialize to obtain the object
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SearchResult));

                System.IO.StringReader strReader = new System.IO.StringReader(msg);
                SearchResult obj = (SearchResult)serializer.Deserialize(strReader);

                //form the event argument
                SearchResultReceivedEventArgs e = new SearchResultReceivedEventArgs(IPAddress.Parse(obj.ipAddResponder), obj.requestId, obj.arlResult);
                //trigger the event
                onSearchResultReceived(this, e);
            }
            catch (XmlException)
            {
            }
        }

    

        

        #region "handle message received"





        private void handleSearchRequest(object sender, NetworkMessage message)
        {
            
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SearchRequest));



            System.IO.StringReader strReader = new System.IO.StringReader(message.MessageContent);

            SearchRequest obj = (SearchRequest)serializer.Deserialize(strReader);

            ReceivedRequest rRequest = new ReceivedRequest(obj.requestId, DateTime.Now, IPAddress.Parse(obj.ipAddSource));
            if (!isDuplicatedRequest(rRequest))
            {
                
                arlOfReceivedRequest.Add(rRequest);
                //process the request by performing searching on local machine
                SearchRequestReceivedEventArgs e = new SearchRequestReceivedEventArgs(obj);
                //signal the event handler
                SearchRequestReceived(sender, e);
            }
             
        }
        private void handleSearchResult(AuthTcpClient client, NetworkMessage message)
        {
            
         
                //deserialize to obtain the object
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SearchResult));

                System.IO.StringReader strReader = new System.IO.StringReader(message.MessageContent);
                SearchResult obj = (SearchResult)serializer.Deserialize(strReader);

                //form the event argument
                SearchResultReceivedEventArgs e = new SearchResultReceivedEventArgs(IPAddress.Parse(obj.ipAddResponder), obj.requestId, obj.arlResult);
                //trigger the event
                onSearchResultReceived(this, e);
          
         
        }

       

        #endregion

        /// <summary>
        /// get the id of the request
        /// </summary>
        /// <returns></returns>
        public int getRequestId()
        {
            DateTime dt = DateTime.Now;
            return int.Parse(dt.Hour.ToString() + dt.Minute.ToString() + dt.Second.ToString());
        }
        /// <summary>
        /// send a search request to the network (to all buddies)
        /// </summary>
        /// <param name="searchObj"></param>
        /// <param name="arlBuddies"></param>
  

      






        
  




       


    
        





         /// <summary>
        /// start listening on the specified port
        /// </summary>
        public void startListening()
        {
            try
            {
                AuthTcpClient authClient = null;
                authServer = new AuthTcpServer(LISTEN_PORT,secretKeyControl, publicKeyControl, friendsControl);
                while (true)
                {
                    try
                    {
                        //listen to the network
                        authClient = authServer.Accept();
                        //Connection conn = new Connection(authClient);
                        //check whether it is authenticated connection
                        Thread thClient=null;
                        if (authClient.IsAuthenticated() == true)
                        {
                            //passed authentication check
                            thClient = new Thread(new ParameterizedThreadStart(AuthClientMethod)) ;        
                        }
                        else
                        {  //failed authentcation process
                           thClient = new Thread(new ParameterizedThreadStart(UnAuthClientMethod)) ; 
                        }
                        thClient.IsBackground = true;
                        thClient.Start(authClient);  
                    }
                    catch
                    {
                        if (authClient != null)
                        {
                            authClient.Close();
                        }
                    }
                }
            }
            catch (SocketException)
            {
                Common.Global.showMsgOneButton("The application can't listen on the port 5150, it has been occupied by another process\r\nClose this process then restart the program.", 'C');
            }
        }

        void UnAuthClientMethod(object client)
        {
            AuthTcpClient authTcpClient = (AuthTcpClient)client;
            try
            {
               
                NetworkMessage message = authTcpClient.receiveMessage();
                //extract the string, get the first character to see the data: what type of message and the xml data inside the message
                int msgType = message.TypeOfMessage;

                switch (msgType)
                {

                        //handle search result
                    case SEARCH_RESULT:
                        {
                            handleSearchResult(authTcpClient, message);
                            break;
                        }
                        //handle download request
                    case DOWNLOAD_REQUEST:
                        {
                            handleDownLoadRequest(authTcpClient, message);
                            break;
                        }
                        //handle verify key response
                    case VERIFYKEY_RESPONSE:
                        {
                            handleKeyVerificationResponseReceived(authTcpClient, message);
                            break;
                        }
                }
            }
            catch
            {
                //error occur termerinate the thread;
                if (authTcpClient != null)
                {
                    authTcpClient.Close();
                }
            }
        

        }

        void AuthClientMethod(object client)
        {
            AuthTcpClient authTcpClient=null;
            try
            {
                authTcpClient = (AuthTcpClient)client;
                NetworkMessage message = authTcpClient.receiveMessage();
                //extract the string, get the first character to see the data: what type of message and the xml data inside the message
                int msgType = message.TypeOfMessage;
                switch (msgType)
                {
                    //handle search request
                    case SEARCH_REQUEST:
                        {
                            handleSearchRequest(authTcpClient, message);
                            break;
                        }
                    case BROWSE_REQUEST:
                        {
                            handleBrowseRequest(authTcpClient, message);
                            break;
                        }
                    //handle search result
                    case SEARCH_RESULT:
                        {
                            handleSearchResult(authTcpClient, message);
                            break;
                        }
                    //handle download request
                    case DOWNLOAD_REQUEST:
                        {
                            handleDownLoadRequest(authTcpClient, message);
                            break;
                        }
                    //handle verify key request
                    case VERIFYKEY_REQUEST:
                        {
                            handleKeyVerificationRequestReceived(authTcpClient, message);
                            break;
                        }
                    //handle feed request
                    case FEED_REQUEST:
                        {
                            handleFeedRequest(authTcpClient, message);
                            break;
                        }
                    //handle view an item request
                    case VIEWITEM_REQUEST:
                        {
                            handleViewAnItemRequest(authTcpClient, message);
                            break;
                        }
                    //handle send message 
                    case SEND_A_MESSAGE:
                        {
                            handleInstantMessageReceived(authTcpClient, message);
                            break;
                        }
                    //handle transfer file request
                    case TRANSFER_FILE_REQUEST:
                        {
                            handleFileTransferRequest(authTcpClient, message);
                            break;
                        }
                }
            }
            catch
            {
                if (authTcpClient != null)
                {
                    authTcpClient.Close();
                }
            }
            finally
            {
                
            }

        }


        /// <summary>
        /// download request
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="message"></param>
        private void handleDownLoadRequest(object sender, NetworkMessage message)
        {
            if (DownloadRequest != null)
            {
                DownloadRequest(sender, message);
            }
        }
   
        /// <summary>
        /// handles key verification request
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleKeyVerificationRequestReceived(object client, NetworkMessage message)
        {
            if(VerifyKeyRequest!=null){
                VerifyKeyRequest(client, message);
            }
        }
        /// <summary>
        /// handles key verification result
        /// </summsary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleKeyVerificationResponseReceived(object client, NetworkMessage message)
        {
            if (VerifyKeyResponse != null)
            {
                VerifyKeyResponse(client, message);
            }
        }
        /// <summary>
        /// handle feed request
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleFeedRequest(object client, NetworkMessage message)
        {
            if (FeedRequestReceived != null)
            {
                FeedRequestReceived(client, message);
            }
        }
        /// <summary>
        /// handles viewAnItem
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleViewAnItemRequest(object client, NetworkMessage message)
        {
            if (ViewAnItemRequest != null)
            {
                ViewAnItemRequest(client, message);
            }
        }

        /// <summary>
        /// handles instant messaging
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleInstantMessageReceived(object client, NetworkMessage message)
        {
            if (InstantMessageReceived != null)
            {
                InstantMessageReceived(client, message);
            }
        }
        /// <summary>
        /// handles file transfer
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleFileTransferRequest(object client, NetworkMessage message)
        {
            if (FileTransferRequestReceived != null)
            {
                FileTransferRequestReceived(client, message);
            }
        }
        /// <summary>
        /// send browse request
        /// </summary>
        /// <param name="ipAdd"></param>
        public void sendBrowseRequest(IPAddress ipAdd)
        {
            String msg = NetworkDealer.BROWSE_REQUEST.ToString() + " " + ipAddMyComputer.ToString();
            Buddy buddy = friendsControl.getAFriendByIP(ipAdd.ToString());
            AuthTcpClient authTcpClient = new AuthTcpClient(ipAdd.ToString(), LISTEN_PORT, buddy.KeyID, secretKeyControl, publicKeyControl, friendsControl);
            try
            {
                authTcpClient.Connect();
                if (authTcpClient.IsAuthenticated() == false)
                {
                    throw new Exception("Not authenticated connection");
                }
                NetworkMessage message = new NetworkMessage();
                message.TypeOfMessage = BROWSE_REQUEST;
                message.MessageContent = ipAddMyComputer.ToString();
                authTcpClient.sendMessage(message);
                //receive a reply from the peer
                message = authTcpClient.receiveMessage();
                //cal no of items;
                int itemNo = int.Parse(message.MessageContent);
                for (int i = 0; i < itemNo; i++)
                {
                    message = authTcpClient.receiveMessage();
                    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SearchResult));

                    System.IO.StringReader strReader = new System.IO.StringReader(message.MessageContent);
                    SearchResult obj = (SearchResult)serializer.Deserialize(strReader);
                    browseResultBuddyReceived(authTcpClient, obj);
                }
            }
            catch
            {

            }
            finally
            {
                authTcpClient.Close();
            }
        }
        /// <summary>
        /// handle browse request
        /// </summary>
        /// <param name="client"></param>
        /// <param name="message"></param>
        private void handleBrowseRequest(object client, NetworkMessage message)
        {

            browseRequestReceived(client, message);
        }
        /// <summary>
        /// send a browse result
        /// </summary>
        /// <param name="arlResult"></param>
        /// <param name="e"></param>

        public void sendBrowseResultItems(object sender, System.Collections.ArrayList arlResult)
        {
            AuthTcpClient client = (AuthTcpClient)sender;
            try
            {

                NetworkMessage message = new NetworkMessage();
                message.TypeOfMessage = BROWSE_RESULT_ITEMS;
                //send back no of items
                message.MessageContent = arlResult.Count.ToString(); ;
                client.sendMessage(message);
                for (int i = 0; i < arlResult.Count; i++)
                {
                    System.Collections.ArrayList arlTemp = new System.Collections.ArrayList();
                    arlTemp.Add(arlResult[i]);
                    //create SearchResult object
                    SearchResult sr = new SearchResult(ipAddMyComputer.ToString(), 0, arlTemp);
                    //serialize the object
                    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SearchResult));
                    System.IO.StringWriter str = new System.IO.StringWriter();
                    serializer.Serialize(str, sr);
                    message.MessageContent = str.ToString();
                    client.sendMessage(message);

                }

            }
            catch { }
            finally
            {
                client.Close();
            }


        }

        //send view item response
        public void sendViewItemResponse(object sender, ResultItem item)
        {
            AuthTcpClient authTcpClient = (AuthTcpClient)sender;
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ResultItem));
            System.IO.StringWriter str = new System.IO.StringWriter();
            item.FileInfoObj.Location = ipAddMyComputer.ToString();
            serializer.Serialize(str, item);
            NetworkMessage message = new NetworkMessage();

            message.TypeOfMessage =VIEWITEM_RESPONSE;
            message.MessageContent = str.ToString();
            authTcpClient.sendMessage(message);
            authTcpClient.Close();
        }
    }
}
